package com.dmp.onlinestore.model.service.impl;

import java.util.ArrayList;
import java.util.List;
import com.dmp.onlinestore.model.service.ProductBeanPager;

import com.dmp.onlinestore.model.dto.ProductBean;

public class ProductBeanPagerImpl implements ProductBeanPager {

	// Default page size;
	private int pageSize = 5;
	
	// Pointers to the first and last items on the page.
	private int pageTop = -1;
	private int pageBottom   = -1;
	
	List<ProductBean> prodList = null;	
	
	// This class is instantiated with a reference to
	// a product list for which is manages paging.
	public ProductBeanPagerImpl(List<ProductBean> prodList) {
		this.prodList = prodList;
	}

	// Returns the size of the managed list. Useful for
	// testing and such.
	public int getManagedListSize() {
	    return prodList.size();
	}
	
	
	// Pages down by one page, or a partial page if fewer than
	// "pageSize" products remain after the current page. If no
	// paging has yet been done, then the first page is returned.
    // If the list of elements this pager is managing is zero,
	// then an empty list is returned.
	public List<ProductBean> pageDown() {
		if (hasMoreDownPages()) {
			// Advance the page top pointer.
			if (getPageTop() == -1) {
				setPageTop(0);
			}
			else {
  			    setPageTop(getPageTop() + getPageSize());
			}
			setPageBottom();
		} // if
		return getCurrentPage();
	} // pageDown


	
	// Positions the pager on the given page number. Page numbers are 
	// 1-based (first available page is page 1) as this
	// is what general users are familiar with.
	// If the given page number is greater than the number
	// of pages available, then the pager is positioned on the last page.
	// If the managed list is empty, or the requested page number is
	// less than 1, then the current page is returned. For an 
	// empty managed list, this means an empty list is returned.
	public List<ProductBean> goToPage(int pageNum) {
		if ((pageNum >= 1) && (prodList.size() > 0)) {
			int newPage = pageNum;
			int testTop = (newPage-1) * getPageSize();
			if (testTop >= prodList.size()) {
				// User is requesting a page greater than the 
				// number of available pages, so give them
				// the last page.
				if ((prodList.size() % getPageSize()) == 0) {
					// Our last page is a full page.
					newPage = prodList.size() / getPageSize();
				}
				else {
					// Our last page is a partial page.
					newPage = (prodList.size() / getPageSize()) + 1;
				}
				setPageTop((newPage-1) * getPageSize());
			}
			else {
				// We're within the range of available pages.
				setPageTop(testTop);
			}
			setPageBottom();
		}
		return getCurrentPage();
	} // gotToPage
	
	
	// Returns true if there is at least one complete or partial
	// page following the current page.
	public boolean hasMoreDownPages() {
		if ((prodList.size()-1) > getPageBottom()) {
			return true;
		}
		else {
			return false;
		}
	}
	
	// Returns true if there is at least one complete or partial
	// page following the current page.
	public boolean hasMoreUpPages() {
		//System.out.println("hasMorePages: top is " + getPageTop() + "; bottom is " + getPageBottom());
		if (getPageTop() > 0) {
			// Top of current page is not the start of the list.
			return true;
		}
		else {
			// Top of current page is the start of the list.
			return false;
		}
	}

	// Pages up by one page. If there are fewer than "pageSize()"
	// elements preceding the current page, then the returned page
	// contains the entries preceding this page, plus the first part
	// of the current page, making a complete page. Ie., the first
	// group of entries on the current page will appear at the end
	// of the newly displayed page. 
	// 
	// If no page has yet been displayed, then an empty list is
	// returned. If the current page is the first page in the list, then
	// this page is returned.
	public List<ProductBean> pageUp() {
		if (hasMoreUpPages()) {
			// Advance the top pointer backwards.
			if (getPageTop() > 0) {
				int testTop = getPageTop() - getPageSize();
				if (testTop < 0) {
					setPageTop(0);
				}
				else {
					setPageTop(testTop);
				}
			}
			setPageBottom();
		}
		return getCurrentPage();
	}
	
	// Resets the page bottom. Uses the current pageTop and pageSize.
	private void setPageBottom() {
		if (getPageTop() != -1) {
			int testBottom = getPageTop() + getPageSize() - 1;
			if (testBottom < (prodList.size()-1)) {
			    setPageBottom(testBottom);
			}
			else {
				setPageBottom(prodList.size()-1);
			}
		}
	}	
	
	public int getPageSize() {
		return pageSize;
	}
	
	// Set the current page size. Returns the current page based on
	// this new page size. Contract is that the invoker will re-display
	// or otherwise process this new/updated page in order that no data 
	// is missed on a future pageDown().
	public List<ProductBean> setPageSize(int pageSize) {
		this.pageSize = pageSize;
		setPageBottom();
		return getCurrentPage();
	}

	private int getPageTop() {
		return pageTop;
	}

	private void setPageTop(int pageTop) {
		this.pageTop = pageTop;
	}

	private int getPageBottom() {
		return pageBottom;
	}

	private void setPageBottom(int pageBottom) {
		this.pageBottom = pageBottom;
	}

	// Returns the current page (does not advance in either direction).
	public List<ProductBean> getCurrentPage() {
		List<ProductBean> newPage = new ArrayList<ProductBean>();
		if (getPageTop() >= 0) {
			for (int i=getPageTop(); i<=getPageBottom(); i++) {
				ProductBean product = prodList.get(i);
				newPage.add(product);
			}
		}
		return newPage;
	}
	
	// Get current page range.
	public String getCurrentPageRange() {
		int numEntries = getManagedListSize();
		int pageSize = getPageSize();
		int lowerBound = getPageTop() + 1;
		if (lowerBound >= 1) {
			int upperBound = lowerBound + pageSize - 1;
			upperBound = (upperBound > numEntries) ? numEntries : upperBound;
			String stringRange = Integer.toString(lowerBound) + "-" + Integer.toString(upperBound);
			return stringRange;
		}
		else {
			return "";
		}
	}

	// Returns a list of strings of indices.
	public List<String> getPageIndices() {
		
		int numEntries = getManagedListSize();
		int pageSize = getPageSize();
		
		System.out.println("num entries is >>" + numEntries + "<<");
		System.out.println("page size is >>" + pageSize + "<<");
		int numPageIndices = numEntries / pageSize;
		System.out.println("numPageIndices is >>" + numPageIndices + "<<");
		numPageIndices += (numEntries % pageSize) == 0 ? 0 : 1;
		System.out.println("numPageIndices is >>" + numPageIndices + "<<");
		
		List<String> returnList = new ArrayList();
		for (int i=0; i < numPageIndices; i++) {
			int lowerBound = (i * pageSize) + 1;
			int upperBound = lowerBound + pageSize - 1;
			upperBound = (upperBound > numEntries) ? numEntries : upperBound;
			String stringRange = Integer.toString(lowerBound) + "-" + Integer.toString(upperBound);
			System.out.println("lb is >>" + lowerBound + "<<  upper bound is >>" + upperBound + "<<");
			System.out.println("string range is >>" + stringRange + "<<");
			returnList.add(stringRange);
		}
		return returnList;
	}

}

// older code ...
//public List<ProductBean> pageDown() {
//	if (prodList.size() == 0) {
//		return null;
//	}
//	// determine the new cursor position.
//	if (cursor == -1) {
//		cursor = 0; // First element in the list.
//	}
//	else {
//		if ((cursor + pageSize) < prodList.size()) {
//			// There are more items after the current page, so
//			// advance the cursor.
//			cursor += pageSize;
//		}
//	}
//	// Determine the last item on the current page.
//    int lastPageItem;
//	if ((cursor + pageSize) >= prodList.size()) {
//		lastPageItem = prodList.size()-1;
//	}
//	else {
//		lastPageItem = cursor + pageSize - 1;
//	}
//	List<ProductBean> newPage = new ArrayList<ProductBean>();
//	for (int i=cursor; i<=lastPageItem; i++) {
//		ProductBean product = prodList.get(i);
//		newPage.add(product);
//	}
//	return null;
//}

